<script lang="ts" setup>
import { ref, watch, computed } from 'vue';

const props = withDefaults(defineProps<{ list: number[]; value?: number }>(), {
  value: 0,
});

const emits = defineEmits<{ (e: 'change', value: number): void }>();

let distance = 0; // 移动距离

let position = 0; // 初始位置

const unit = 'vh'; // 单位

const speed = 6; // 滑动速度倍速

const columnsHeight = 30; // 列总高度

const rowHeight = 6; // 行高度

const current = ref(props.value); // 当前选中列的下标

const offset = ref(0); // 偏移量

const columnsStyle = computed(() => ({
  top: `${offset.value}${unit}`,
}));

const computedOffset = (value?: number) => {
  if (value) current.value = value;
  // 选中行的位置为：当前列下标*行高+列居中位置-行居中位置
  offset.value =
    -(current.value * rowHeight) + columnsHeight / 2 - rowHeight / 2;
};

/**
 * 初始化
 */
const init = () => {
  // 当下标越界，则重置为最大下标
  if (props.list[props.value]) {
    current.value = props.value;
  } else {
    current.value = props.list.length - 1;
  }

  computedOffset();
};

/**
 * 按下
 */
const handleDown = (event: TouchEvent) => {
  distance = event.touches[0].clientY / speed;
  position = offset.value;
};

/**
 * 移动
 */
const handleMove = (event: TouchEvent) => {
  offset.value = position + event.touches[0].clientY / speed - distance;
};

/**
 * 松开
 */
const handleUp = (event: TouchEvent) => {
  position = distance = 0;
  const _current = -(
    Math.round((offset.value - columnsHeight / 2) / rowHeight) + 1
  );

  // 判断是否超过最大下滑位置或最大上滑位置
  if (_current < 0) {
    current.value = 0;
  } else if (_current > props.list.length - 1) {
    current.value = props.list.length - 1;
  } else {
    // 根据位置重新计算当前行下标
    // 当前下标=四舍五入（当前位置/行高度）
    current.value = _current;
  }

  computedOffset();
  emits('change', current.value);
};

/**
 * 判断是否选中
 */
const isSelected = (value: number) => {
  return value === current.value;
};

watch(
  () => props.value,
  () => init(),
  { immediate: true }
);

defineExpose({ computedOffset });
</script>

<template>
  <div class="date-column">
    <section
      class="date-column__columns"
      :style="columnsStyle"
      @touchstart="(event: TouchEvent) => handleDown(event)"
      @touchmove="(event: TouchEvent) => handleMove(event)"
      @touchend="(event: TouchEvent) => handleUp(event)"
    >
      <section
        class="date-column__row"
        :class="{ 'date-column__row--selected': isSelected(index) }"
        v-for="(item, index) in list"
        :key="index"
      >
        <slot name="defualt" :item="item"> </slot>
      </section>
    </section>
  </div>
</template>

<style scoped lang="scss">
.date-column {
  position: relative;
  width: 100%;
  height: 30vh;
  overflow: hidden;

  &:after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(
      rgba(255, 255, 255, 0.9) 0,
      transparent 50%,
      rgba(255, 255, 255, 0.9) 100%
    );
    pointer-events: none;
    z-index: 99;
  }

  &__columns {
    position: absolute;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: 10;
    transition: 100ms;
  }

  &__row {
    display: flex;
    justify-content: center;
    align-items: center;

    box-sizing: border-box;
    width: 100%;
    height: 6vh;
    text-align: center;
    font-size: 12px;
    transition: 200ms;

    &--selected {
      font-weight: bold;
      color: #7951f8;
    }
  }
}
</style>
